#include "rtspstream.h"
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include "httpserver.h"
#include "rtspstreammanage.h"
#include "globalvariable.h"
#include "tools.h"

/*========================================================== 
    函数名 ：   CBHandleHttpRtspReq
    功能 ：		处理http rtsp相关请求操作，作为线程执行体使用
    算法实现 ： <可选项> 
    参数说明 ： void*   pArg     [in]    http请求参数，实际内容未结构体（HttpPostBodyInfo）
    返回值说明：
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
void CBHandleHttpRtspReq(void *pArg)
{
    if(NULL == pArg)
    {
        TRACE_DEBUG("pArg == NULL invalid param");
        return ;
    }

    // 判断是否已经存在连接sessionid
    PHttpPostBodyInfo ptPostBodyInfo = ((PHttpPostBodyInfo)pArg);
    // rtsp stream manage 加锁(判断节点是否存在，与添加节点，要在临界区执行)
    RtspStreamManageLock(g_ptRtspStreamManage);
    int nExistsSession = ExistsRtspStreamItem(g_ptRtspStreamManage,ptPostBodyInfo->nSessionId);
    if(0 == nExistsSession) // 连接不存在
    {
        // 添加连接节点
        AppendRtspStreamItemInfo(g_ptRtspStreamManage,ptPostBodyInfo->nSessionId,ptPostBodyInfo->achUrl,ptPostBodyInfo->achPlayType);
        // rtsp stream manage 解锁
        RtspStreamManageUnLock(g_ptRtspStreamManage);
        // 创建新的rtsp流
        int nCreateStreamRet = CreateNewRtspStream(ptPostBodyInfo);
        if(-1 == nCreateStreamRet)
        {
            TRACE_DEBUG("create rtsp stream failed");
            DeleteRtspStreamItem(g_ptRtspStreamManage,ptPostBodyInfo->nSessionId);
            free(ptPostBodyInfo);
        }
    }
    else    // 存在连接
    {
        // rtsp stream manage 解锁
        RtspStreamManageUnLock(g_ptRtspStreamManage);
        // 后续处理。。。
    }
    return ;
}


/*========================================================== 
    函数名 ：   CreateNewRtspStream
    功能 ：		创建新的rtsp拉流
    算法实现 ： <可选项> 
    参数说明 ： PHttpPostBodyInfo   ptPostInfo     [in]    http请求参数
    返回值说明：-1 失败 0 成功（成功状态会阻塞执行，不会返回到这里)
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
int CreateNewRtspStream(PHttpPostBodyInfo ptPostInfo)
{
    // 解析url中服务器ip 端口
    char achIp[POST_PARAM_VAL_BUF_LEN] = {0};
    int nPort = 0;
    int nParseIpPort = ParseServerIpPort(ptPostInfo->achUrl,achIp,&nPort);
    if(-1 == nParseIpPort)
    {
        return -1;
    }
    
    // 创建rtsp socket 连接
    int nSocketFd = CreateSocket(AF_INET,SOCKET_STREAM);
    if(-1 == nSocketFd)
    {
        return -1;
    }

    //连接服务器
    struct sockaddr_in tServaddr;
    memset(&tServaddr, 0, sizeof(tServaddr));
    tServaddr.sin_family = AF_INET;
    tServaddr.sin_addr.s_addr = inet_addr(achIp);
    tServaddr.sin_port = htons(nPort);  //服务器端口
    int nConnectRet = connect(nSocketFd,(struct sockaddr*)&tServaddr,sizeof(tServaddr));
    if(-1 == nConnectRet)
    {
        TRACE_DEBUG("connect the server failed.\n");
        close(nSocketFd);
        return -1;
    }

    // 发送OPTIONS 选项
    char achBuf[]
    
    /***************** OPTIONS *************************/
    memset(buf,0,CMD_LEN);
    printf("3\n");
    sprintf(buf,GetRTSPCmd("OPTIONS"),RTSP_URL,1,"User-Agent: myrtsp");
    SendRTSPCmd(sock_fd, "OPTIONS",buf);
    ReadSocket(sock_fd,buf,CMD_LEN,10);

    /***************** DESCRIBE *************************/
    memset(buf,0,CMD_LEN);
    sprintf(buf,GetRTSPCmd("DESCRIBE"),RTSP_URL,"Accept: application/sdp", 2, "User-Agent: myrtsp");
    SendRTSPCmd(sock_fd, "DESCRIBE", buf);
    memset(buf,0,CMD_LEN);
    ReadSocket(sock_fd,buf,CMD_LEN,10);

    /***************** SETUP *************************/
    memset(buf,0,CMD_LEN);
    sprintf(buf,
            "SETUP rtsp://%s:%d/554\r\n"
            "CSeq: 1\r\n"
            "Transport: RTP/AVP/UDP;unicast;client_port=57104-57105\r\n\r\n",SERVER_IP,SERVER_PORT);
    SendRTSPCmd(sock_fd, "SETUP", buf);
    ReadSocket(sock_fd,buf,CMD_LEN,10);


    //get the session and server port
    char psession[50],pserverport[10];
    char* ptr;
    memset(psession,0,50);
    memset(pserverport,0,10);
    ptr=strstr(buf,"Session:");
    if(ptr==0)
    {
        printf("cannot find the session.\n");
        return 0;
    }
    memcpy(psession,ptr+strlen("Session:"),strstr(ptr,"\r\n")-ptr-strlen("Session:"));
    printf("Session:%s\n",psession);
    ptr=strstr(buf,"server_port=");
    memcpy(pserverport,ptr+strlen("server_port="),strstr(ptr,"-")-ptr-strlen("server_port="));
    printf("Server port: %s\n",pserverport);
    printf("\n");

    /***************** PLAY *************************/
    memset(buf,0,CMD_LEN);
    sprintf(buf,GetRTSPCmd("PLAY"),RTSP_URL,1,psession,"Range: npt=0.000-\r\n","","","");
    SendRTSPCmd(sock_fd, "PLAY", buf);
    ReadSocket(sock_fd,buf,CMD_LEN,10);

    /*    接收数据用udp       */
    struct sockaddr_in addr_stream;
    struct sockaddr_in addr_local;
    int recv_fd=socket(AF_INET,SOCK_DGRAM,0);
    if(recv_fd==-1)
    {
        printf("create the stream socket failed.\n");
        return 0;
    }

    addr_local.sin_family=AF_INET;
    // addr_local.sin_addr.s_addr=inet_addr("192.168.1.126");
    addr_local.sin_addr.s_addr=INADDR_ANY;
    //监听本地端口号
    addr_local.sin_port=htons(57104);
    int len_addr_local=sizeof(addr_local);
    if(bind(recv_fd,(struct sockaddr*)&addr_local,len_addr_local)==-1)
    {
        printf("bind the local stream socket failed.\n");
        return 0;
    }

    addr_stream.sin_family=AF_INET;
    addr_stream.sin_addr.s_addr=inet_addr(SERVER_IP);
    addr_stream.sin_port=htons(atoi(pserverport));
    int len_recv;
    int len_addr=sizeof(addr_stream);
    int count = 0;


    //    FILE *save_fd = fopen("/tmp/test.264", "wb");
    while(1)
    {
        memset(rbuf, 0, RECV_LEN);

        len_recv = recvfrom(recv_fd, rbuf, RECV_LEN, 0, (struct sockaddr*)&addr_stream, &len_addr);
        // printf("len_recv:%d\n", len_recv);
        if(len_recv == -1)
        {
            printf("recvfrom the stream failed.\n");
            return 0;
        }

        char *p = rbuf;
        char *data = h264_data;
        unsigned char frame_end = rbuf[1] >> 7;
        unsigned char frame_start_flag = rbuf[13] & 0x80;
        unsigned char frame_end_flag = rbuf[13] & 0x40;
        #if 0
        memcpy(data + h264_data_len, p + 14, len_recv - 14);
        h264_data_len += len_recv - 14;

        // printf("rbuf[1]:%x\n", rbuf[1]);
        // printf("rbuf[13]:%x\n", rbuf[13]);
        // printf("frame_end_flag:%x\n", frame_end_flag);
//        0                            是F
//        11                          是NRI
//        11100                    是FU Type，这里是28，即FU-A
//        1                            是S，Start，说明是分片的第一包
//        0                            是E，End，如果是分片的最后一包，设置为1，这里不是
//        0                            是R，Remain，保留位，总是0
//        00101                    是NAL Type，这里是5，说明是关键帧（不知道为什么是关键帧请自行谷歌）

//        int w_ret = fwrite(p + 14, len_recv - 14, 1, save_fd);
        if(frame_end_flag == 0x40)
        {
        //    printf("h264_data_len:%d\n", h264_data_len);
            _data_callback->push_data((uint8_t *)(h264_data), (int16_t)1920, (int16_t)1080, (int32_t)h264_data_len);
           int w_ret = fwrite(h264_data, h264_data_len, 1, save_fd);

            h264_data_len = 0;
            memset(h264_data, 0, 102400);
        }
        #else
        // printf("rbuf[12]:%x rbuf[13]:%x\n", rbuf[12], rbuf[13]);
        if((rbuf[12] == 0x7c) && (frame_end_flag == 0x40))//如果是尾就发送
        {
            memcpy(data + h264_data_len, p + 14, len_recv - 14);
            h264_data_len += len_recv - 14;
                    //    printf("pack h264_data_len:%d\n", h264_data_len);
            _data_callback->push_data((uint8_t *)(h264_data), (int16_t)1280, (int16_t)720, (int32_t)h264_data_len);
            // int w_ret = fwrite(h264_data, h264_data_len, 1, save_fd);

            h264_data_len = 0;
            memset(h264_data, 0, 102400);
            continue;
        }
        if(rbuf[13] == 0x81)  //P帧
        {
            h264_data[h264_data_len] = 0x00;
            h264_data[h264_data_len + 1] = 0x00;
            h264_data[h264_data_len + 2] = 0x00;
            h264_data[h264_data_len + 3] = 0x01;
            h264_data[h264_data_len + 4] = 0x61;
            h264_data_len = h264_data_len + 5;
        }

        if(rbuf[13] == 0x85)  //I帧
        {
            h264_data[h264_data_len] = 0x00;
            h264_data[h264_data_len + 1] = 0x00;
            h264_data[h264_data_len + 2] = 0x00;
            h264_data[h264_data_len + 3] = 0x01;
            h264_data[h264_data_len + 4] = 0x65;
            h264_data_len = h264_data_len + 5;
        }

        if((rbuf[12] == 0x67) && (rbuf[13] == 0x42))  //SPS帧
        {
            h264_data[h264_data_len] = 0x00;
            h264_data[h264_data_len + 1] = 0x00;
            h264_data[h264_data_len + 2] = 0x00;
            h264_data[h264_data_len + 3] = 0x01;
            h264_data[h264_data_len + 4] = 0x67;
            h264_data[h264_data_len + 5] = 0x42;
            h264_data_len = h264_data_len + 6;
        }

        if((rbuf[12] == 0x68) && (rbuf[13] == 0xce))  //PPS帧
        {
            h264_data[h264_data_len] = 0x00;
            h264_data[h264_data_len + 1] = 0x00;
            h264_data[h264_data_len + 2] = 0x00;
            h264_data[h264_data_len + 3] = 0x01;
            h264_data[h264_data_len + 4] = 0x68;
            h264_data[h264_data_len + 5] = 0xce;
            h264_data_len = h264_data_len + 6;
        }

        if((rbuf[12] == 0x06))  //补全后的SEI  补充增强信息
        {
            h264_data[h264_data_len] = 0x00;
            h264_data[h264_data_len + 1] = 0x00;
            h264_data[h264_data_len + 2] = 0x00;
            h264_data[h264_data_len + 3] = 0x01;
            h264_data[h264_data_len + 4] = rbuf[12];
            h264_data[h264_data_len + 5] = rbuf[13];
            h264_data_len = h264_data_len + 6;
        }

        memcpy(data + h264_data_len, p + 14, len_recv - 14);
        h264_data_len += len_recv - 14;
        #endif
    }

}


/*========================================================== 
    函数名 ：   ParseServerIpPort
    功能 ：		解析url中的ip，端口
    算法实现 ： <可选项> 
    参数说明 ：  char*   pchUrl     [in]    url地址
                char*   pchIp       [out]   传出ip地址
                int*    pnPort      [out]   传出端口号
    返回值说明： 0 成功 -1 失败
    ------------------------------------------------------------------------------------------------------- 
    修改记录 ： 日 期 版本 修改人 走读人 修改记录
    1998/09/15 V1.0 某某（中文） 某某（中文） 记录关键内容
===========================================================*/
int ParseServerIpPort(char *pchUrl,char *pchIp,int *pnPort)
{
    if(NULL == pchUrl || NULL == pchIp || NULL == pnPort)
    {
        return -1;
    }
    // 127.0.0.1:554
    char *pSplit = strstr(pchUrl,":");
    if(NULL == pSplit)
    {
        return -1;
    }
    int nIpLen = pSplit - pchUrl;
    strncpy(pchIp,pchUrl,nIpLen);
    pchIp[nIpLen] = '\0';
    *pnPort = atoi(pSplit + 1)；
    return 0;
}